﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.Linq;

namespace UnitSoftware.LINQ2SQLExtentions
{
    public class DataChangeProcessor 
    {
        public readonly static DataChangeProcessor INSTANCE = new DataChangeProcessor();

        public event EventHandler<EntitiesEventArgs> EntitiesUpdated;
        public event EventHandler<EntitiesEventArgs> EntitiesDeleted;
        public event EventHandler<EntitiesEventArgs> EntitiesInserted;
        public event EventHandler<DataContextEventArgs> OnSubmitChangesComplete;

        public SubmitChangesResult Persist<TEntity>(DataContext context, RefreshMode refreshMode, TEntity entity) where TEntity : class
        {
            Table<TEntity> table = ((Table<TEntity>)context.GetTable(entity.GetType()));

            if (!table.Contains(entity))
                table.InsertOnSubmit(entity);

            return SubmitChanges(context, refreshMode);
        }

        public SubmitChangesResult SubmitChanges(DataContext context, RefreshMode refreshMode)
        {
            ChangeSet changeSet = context.GetChangeSet();
            SubmitChangesResult changes = new SubmitChangesResult();

            if (changeSet.Updates.Count==0 && changeSet.Inserts.Count==0 && changeSet.Deletes.Count==0)
                return changes;
            else
            {
                changes.Deletes.AddRange(changeSet.Deletes);
                changes.Updates.AddRange(changeSet.Updates);
                changes.Inserts.AddRange(changeSet.Inserts);
            }

            using (TransactionScope ts = new TransactionScope())
            {
                try
                {
                    context.SubmitChanges(ConflictMode.ContinueOnConflict);
                }
                catch (ChangeConflictException)
                {
                    changes.Conflicts.AddRange(context.ChangeConflicts);

                    foreach (ObjectChangeConflict conflict in changes.Conflicts)
                    {
                        if (conflict.IsDeleted)
                        {
                            changes.Deletes.Add(conflict.Object);
                            changes.Updates.Remove(conflict.Object);
                        }

                        conflict.Resolve(refreshMode, true);
                    }
                }

                ts.Complete();
            }

            if (EntitiesDeleted != null && changes.Deletes.Count>0)
                EntitiesDeleted(this, new EntitiesEventArgs(changes.Deletes, context));

            if (EntitiesUpdated != null && changes.Updates.Count > 0)
                EntitiesUpdated(this, new EntitiesEventArgs(changes.Updates, context));

            if (EntitiesInserted != null && changes.Inserts.Count > 0)
                EntitiesInserted(this, new EntitiesEventArgs(changes.Inserts, context));

            if (OnSubmitChangesComplete != null)
                OnSubmitChangesComplete(this, new DataContextEventArgs(context));

            return changes;
        }
    }
}
